﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Core.Config;
using TouchSocket.Core.Log;
using TouchSocket.Core.Run;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;

namespace Updater.Core
{
    public class UPTcpClient
    {
        private TcpTouchRpcClient client;
        public TcpTouchRpcClient Client { get { return client; } }
        /// <summary>
        /// 构造函数
        /// </summary>
        public UPTcpClient(string ip,int port)
        {
            client=new TcpTouchRpcClient();
            TouchSocketConfig config=new TouchSocketConfig();
            //设置服务器地址
            config.SetRemoteIPHost(ip + ":" + port.ToString());
            //设置token
            config.SetVerifyToken("TouchRpc");
           

            client.Setup(config);
            
            client.FileTransfering += (client, e) =>
            {
                //有可能是上传，也有可能是下载
                Console.WriteLine ($"服务器请求传输文件，ID={client.ID}，请求类型={e.TransferType}，文件名={e.FileInfo.FileName}");
            };

            client.FileTransfered += (client, e) =>
            {
                //传输结束，但是不一定成功，需要从e.Result判断状态。
                Console.WriteLine($"服务器传输文件结束，ID={client.ID}，请求类型={e.TransferType}，文件名={e.FileInfo.FileName}，请求状态={e.Result}");
            };

        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <returns></returns>
        public bool Connetc()
        {
            if (client.IsHandshaked)
            {
                return  true;
            }
            else
            {
                try
                {
                    client.Connect();
                }
                catch (Exception)
                {
                    this.Message("连接不到服务器");
                    return false;
                }
            }
          
            return client.IsHandshaked;
        }
        public void Message(string str) 
        {
            client.Logger.Message(str);
        }
        /// <summary>
       /// 从服务器下载文件
       /// </summary>
       /// <param name="Path">远程路径</param>
       /// <param name="SavePath">本地保存路径</param>
        public async Task<string> DownloadFile(string Path,string SavePath)
        {
            if (!this.Connetc())
            {
                Message("连接不到服务器，请检查通讯");
            }


            FileRequest fileRequest = new FileRequest(Path, SavePath);
            fileRequest.Flags = TransferFlags.BreakpointResume;//尝试断点续传，使用断点续传时，会验证MD5值

            FileOperator fileOperator = new FileOperator();//实例化本次传输的控制器，用于获取传输进度、速度、状态等。

            fileOperator.Timeout = 60 * 1000;//当传输大文件，且启用断点续传时，服务器可能会先计算MD5，而延时响应，所以需要设置超时时间。

            //此处的作用相当于Timer，定时每秒输出当前的传输进度和速度。
            LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
            {
                if (fileOperator.Result.ResultCode != ResultCode.Default)
                {
                    loop.Dispose();
                }
                
                long speed = fileOperator.Speed();
                
                if (speed <= 1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed}b/S");
                }
                if (speed > 1024 && speed <= 1024 * 1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed / 1024}Kb/S");
                }
                if (speed > 1024 * 1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed / 1024 / 1024}Mb/S");
                }

            });

           

            Metadata metadata = new Metadata();//传递到服务器的元数据
            metadata.Add("1", "1");
            metadata.Add("2", "2");

            //此方法会阻塞，直到传输结束，也可以使用PullFileAsync
            Task< Result> result = client.PullFileAsync(fileRequest, fileOperator, metadata);
            await loopAction.RunAsync();
            await result;
            return result.Result.Message;
        }

        /// <summary>
        /// 下载时候提示文件总数和当前文件
        /// </summary>
        /// <param name="Path"></param>
        /// <param name="SavePath"></param>
        /// <param name="index"></param>
        /// <param name="count"></param>
        public async Task<string> DownloadFile(string Path, string SavePath,int index,int count)
        {
            if (!this.Connetc())
            {
                Message("连接不到服务器，请检查通讯");
            }
            FileRequest fileRequest = new FileRequest(Path, SavePath);
            fileRequest.Flags = TransferFlags.BreakpointResume;//尝试断点续传，使用断点续传时，会验证MD5值
            FileOperator fileOperator = new FileOperator();//实例化本次传输的控制器，用于获取传输进度、速度、状态等。
            fileOperator.Timeout = 60 * 1000;//当传输大文件，且启用断点续传时，服务器可能会先计算MD5，而延时响应，所以需要设置超时时间。
            //此处的作用相当于Timer，定时每秒输出当前的传输进度和速度。
            LoopAction loopAction = LoopAction.CreateLoopAction(-1, 100, (loop) =>
            {
                if (fileOperator.Result.ResultCode != ResultCode.Default)
                {
                    
                        loop.Dispose();
                }
                long speed = fileOperator.Speed();
                if (speed <= 1024)
                {
                    client.Logger.Message($"{(index * 100 / count).ToString("f2")}%,下载{Path.Substring(Path.LastIndexOf("\\") +1)}，进度：{fileOperator.Progress * 100}%，速度：{speed}b/S，当前第{index}文件，共{count}文件");
                }
                if (speed > 1024 && speed <= 1024 * 1024)
                {
                    client.Logger.Message($"{(index * 100 / count ).ToString("f2")}%,下载{Path.Substring(Path.LastIndexOf("\\") + 1)}，进度：{fileOperator.Progress * 100}%，速度：{speed / 1024}Kb/S，当前第{index}文件，共{count}文件");
                }
                if (speed > 1024 * 1024)
                {
                    client.Logger.Message($"{(index * 100 / count ).ToString("f2")}%,下载{Path.Substring(Path.LastIndexOf("\\") + 1)}，进度：{fileOperator.Progress * 100}%，速度：{speed / 1024 / 1024}Mb/S，当前第{index}文件，共{count}文件");
                }
            });
            Task task= loopAction.RunAsync();
            Metadata metadata = new Metadata();//传递到服务器的元数据
            metadata.Add("1", "1");
            metadata.Add("2", "2");
            //此方法会阻塞，直到传输结束，也可以使用PullFileAsync

            Task<Result> result = client.PullFileAsync(fileRequest, fileOperator, metadata);
            task.Wait();
            await result;
           // client.Logger.Message($"下载：{Path}，返回结果：{result.Result.Message}");
            return result.Result.Message;
        }


        public async Task<string> UpdateFile(string Path,string SavePath)
        {
            if (!this.Connetc())
            {
                Message("连接不到服务器，请检查通讯");
                return "";
            } 
            FileRequest fileRequest = new FileRequest(Path, SavePath);
            
            fileRequest.Flags = TransferFlags.BreakpointResume;//尝试断点续传，使用断点续传时，会验证MD5值

            FileOperator fileOperator = new FileOperator();//实例化本次传输的控制器，用于获取传输进度、速度、状态等。

            fileOperator.Timeout = 60 * 1000;//当传输大文件，且启用断点续传时，服务器可能会先计算MD5，而延时响应，所以需要设置超时时间。

            //此处的作用相当于Timer，定时每秒输出当前的传输进度和速度。
            LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
            {
                if (fileOperator.Result.ResultCode != ResultCode.Default)
                {
                    loop.Dispose();
                }
                long speed = fileOperator.Speed();
                
                if (speed<=1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed}b/S");
                }
                if (speed>1024&&speed<=1024*1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed / 1024}Kb/S");
                }
                if(speed >1024 * 1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed / 1024 / 1024}Mb/S");
                }
               
            });

           

            Metadata metadata = new Metadata();//传递到服务器的元数据,默认token
            metadata.Add("token", "123");

            //此方法会阻塞，直到传输结束，也可以使用PullFileAsync
            Task< Result> result = client.PushFileAsync(fileRequest, fileOperator,metadata);
            
            await loopAction.RunAsync();
            await result;
            return result.Result.Message;
        }
        /// <summary>
        /// 指定密钥进行上传(密钥用于验证）
        /// </summary>
        /// <param name="Path"></param>
        /// <param name="SavePath"></param>
        /// <param name="matedata"></param>
        public async Task<string> UpdateFile(string Path,string SavePath, string token)
        {
            if (!this.Connetc())
            {
                Message("连接不到服务器，请检查通讯");
            }
            FileRequest fileRequest = new FileRequest(Path, SavePath);

            fileRequest.Flags = TransferFlags.BreakpointResume;//尝试断点续传，使用断点续传时，会验证MD5值

            FileOperator fileOperator = new FileOperator();//实例化本次传输的控制器，用于获取传输进度、速度、状态等。

            fileOperator.Timeout = 60 * 1000;//当传输大文件，且启用断点续传时，服务器可能会先计算MD5，而延时响应，所以需要设置超时时间。

            //此处的作用相当于Timer，定时每秒输出当前的传输进度和速度。
            LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
            {
                if (fileOperator.Result.ResultCode != ResultCode.Default)
                {
                    loop.Dispose();
                }
                long speed = fileOperator.Speed();

                if (speed <= 1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed}b/S");
                }
                if (speed > 1024 && speed <= 1024 * 1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed / 1024}Kb/S");
                }
                if (speed > 1024 * 1024)
                {
                    client.Logger.Message($"进度：{fileOperator.Progress * 100}%，速度：{speed / 1024 / 1024}Mb/S");
                }

            });

           

            Metadata metadata = new Metadata();//传递到服务器的元数据
            metadata.Add("token", token);

            //此方法会阻塞，直到传输结束，也可以使用PullFileAsync
            Task<Result>  result = client.PushFileAsync(fileRequest, fileOperator, metadata);
            await loopAction.RunAsync();
            await result;
           
            return result.Result.Message;
        }
    }
}
